home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
msysjour
/
vol07
/
04
/
open
/
open.c
< prev
next >
Wrap
Text File
|
1992-07-01
|
11KB
|
381 lines
/*
Copyright 1991 by David Thielen, All Rights Reserved.
This code example is from a commercial product and has restricted
rights. This code, or any code derived from this code may be
incorporated into any programs with the following restrictions;
1) It cannot be sold as source code, and 2) It cannot be sold in a
product which provides this code as an API.
*/
// If we create a R/O file & we want to write to it - we use the create
// and live with bad sharing.
#include "file_io.h"
#include "stdlib.h"
#include "string.h"
union U_TIME
{
char sTime[4];
long lTime;
};
int FileOpen (BYTE *pFile,unsigned uMode,unsigned short uAtr,
unsigned *puErr)
{
int iRtn, iTries, fRO;
unsigned uFileMode, uOpenMode, uErr;
BYTE *pName, *pErr;
union U_TIME uTime;
#ifdef DEBUG
if ((! pFile) || (! *pFile) || (! puErr) ||
(! (uMode & (O_READ | O_WRITE))) ||
(! (uMode & (O_OPEN | O_CREATE | O_TEMP))))
DebugPrintf ("OpenName (%s, %X, %X, %X)\n", pFile, uMode, uAtr, puErr);
#endif
// We do some simple parameter checking. This stops us from passing
// bad params to DOS & saves us the time of an open if we know it will
// fail.
if ((! (uMode & (O_OPEN | O_CREATE | O_TEMP))) || (! *pFile))
{
*puErr = 0x57;
return (-1);
}
// Check to see if we may be creating a R/O file that we want
// to write to
if ((uAtr & A_READ_ONLY) && (uMode & (O_CREATE | O_TEMP)) &&
(uMode & O_WRITE))
fRO = -1;
else
fRO = 0;
// First, lets set up the mode word - we still use the low byte of
// it in pre-DOS 4.
uFileMode = 0;
switch (uMode & (O_READ | O_WRITE))
{
case O_READ | O_WRITE :
uFileMode |= 0x02;
break;
case O_WRITE :
uFileMode |= 0x01;
break;
// O_READ is 0 - if neither set -> default to this
}
switch (uMode & (S_DENY_READ | S_DENY_WRITE))
{
case S_DENY_READ | S_DENY_WRITE :
uFileMode |= 0x10;
break;
case S_DENY_READ :
uFileMode |= 0x30;
break;
case S_DENY_WRITE :
uFileMode |= 0x20;
break;
// Set to DENY_NONE, not compatibility mode
default :
uFileMode |= 0x40;
break;
}
if (uMode & S_DENY_CHILD)
uFileMode |= 0x80;
// If temp - ignore OPEN & CREATE
if (uMode & O_TEMP)
{
uMode |= O_OPEN; // set O_OPEN for below
// make sure path ends with '\', point to end of path
pName = pErr = pFile + strlen (pFile);
if (*(pName-1) != '\\')
*pName++ = '\\';
#ifdef DEBUG
memset (pName, '$', 12); // make sure big enough buffer
#endif
// lets create it
if (DosMajVer >= 3)
{
*pName = 0; // In case added '\'
_asm
{
mov ax, 5A00h
mov cx, [uAtr]
mov dx, [pFile]
int 21h // Create temp file
mov [iRtn], ax
mov [uErr], 0
jnc dne1
mov [uErr], ax
dne1:
}
if ((*puErr = uErr) != 0) // Create failed
{
*pErr = 0; // Set to passed in string
return (-1); // Return the error
}
// If set to R/O, O_WRITE - use this handle
if (fRO)
return (iRtn);
// close file, drop to below to open with share
FileClose (iRtn);
}
else
// < DOS 3.0
// We need to create a temp file - we use the time to build a
// name & find-first to see if it exists. We only try 5 times
// because we are time based - using the system clock.
{
*puErr = 0x12;
for (iTries=0; iTries<5; iTries++)
{
// get a name
_asm
{
mov ah, 2Ch
int 21h // System time
mov word ptr [uTime], dx
mov word ptr [uTime+2], cx
}
uTime.sTime[0] -= (char) iTries; // Subtract try - clock frozen
ltoa (uTime.lTime, pName, 36); // Convert to 7 digit string
// does it exist?
_asm
{
mov ah, 4Eh
mov cx, 27h
mov dx, [pFile]
int 21h // Find First
mov [uErr], 0
jnc dne2
mov [uErr], ax
dne2:
}
// An error other than ! file
if ((uErr) && (uErr != 0x12))
{
*puErr = uErr;
*pErr = 0;
return (-1);
}
// If it doesn't exist - create it
if (uErr == 0x12)
{
_asm
{
mov ah, 3Ch
mov cx, [uAtr]
mov dx, [pFile]
int 21h // Create
mov [iRtn], ax
mov [uErr], 0
jnc dne3
mov [uErr], ax
dne3:
}
// Since share doesn't exist in DOS 2 - we return the CREATE
// handle - no point in doing an open for sharing.
if (! (*puErr = uErr))
return (iRtn);
}
}
// Couldn't create a temp file. Return the passed in string
*pErr = 0;
return (-1);
}
}
// OPEN/CREATE - either from temp or O_OPEN/O_CREATE
// If DOS >= 4.0 - use func 6Ch
// OS/2 is DOS version 10 - we treat that like DOS 3.3
if ((DosMajVer >= 4) && (DosMajVer != 10))
{
// We set the critical error handling to always go to int 24 for 2
// reasons. First, we want to be version independent and since we
// can't skip int 24 for all versions, we need to hit int 24 in all
// versions on critical errors. Second, ignoring int 24 is not
// handled consistently by DOS on all file handle calls and int 24
// will still be called in some erro cases even if the bit is set.
uOpenMode = 0;
// func 6C - can cause all writes to be a commit. ONLY use this if
// you TRUELY need all writes to be committed - this is EXPENSIVE.
// If even 1 write out of 10 does not need to be committed, don't
// use this bit and call FileCommit the other 9 times.
if (uMode & O_COMMIT)
uFileMode |= 0x4000;
// These bits decide what to do if the file does/doesn't exist.
if (uMode & O_OPEN)
{
if (uMode & O_TRUNC)
uOpenMode |= 0x02; // Replace if exists
else
uOpenMode |= 0x01; // Open if exists
}
if (uMode & O_CREATE)
uOpenMode |= 0x10; // Create if ! exists
// lets open it
_asm
{
mov ax, 6C00h
mov bx, [uFileMode]
mov cx, [uAtr]
mov dx, [uOpenMode]
mov si, [pFile]
int 21h // extended open
mov [iRtn], ax
mov [uErr], 0
jnc dne4
mov [uErr], ax
dne4:
}
// We got it - lets return it
if ((*puErr = uErr) != 0)
return (-1);
}
else
// OK - we don't have the DOS 4+ super-duper one size fits all open,
// we have to use (create &) open.
{
// first we try an open - if we are on an exclusive create, we need
// to know if we need to fail, otherwise, we are in business.
uErr = 0;
_asm
{
mov ah, 3Dh
mov al, byte ptr [uFileMode]
mov dx, [pFile]
int 21h // Open
mov [iRtn], ax
jnc dne5
mov [uErr], ax
dne5:
}
*puErr = uErr;
// We now use the following logic:
// 1) If O_OPEN & we were successful - we've got it
// else 2) If ! O_CREATE & we failed - we return -1
// else 3) if O_CREATE & we were successful - we return -1
// 1) If O_OPEN & we were successful - we've got it
if ((uMode & O_OPEN) && (! uErr))
goto Finish; // Opened file
// 2) If ! O_CREATE & we failed - we return -1
if ((! (uMode & O_CREATE)) && (uErr))
return (-1);
// 3) if O_CREATE & we were successful - we return -1
// Since O_CREATE must be true here - we don't test for it
if (! uErr)
{
FileClose (iRtn);
*puErr = 0x50; // File already exists
return (-1); // Return error
}
// We know the file doesn't exist AND O_CREATE is set
// So its time to create it. For 3.0+ we use the newer create
// in case we are in Windows & someone else creates it right now.
uErr = 0;
if (DosMajVer >= 3)
_asm
{
mov ah, 5Bh
mov cx, [uAtr]
mov dx, [pFile]
int 21h // Create - can't exist
mov [iRtn], ax
jnc dne6
mov [uErr], ax
dne6:
}
else
_asm
{
mov ah, 3Ch
mov cx, [uAtr]
mov dx, [pFile]
int 21h // Create - may exist
mov [iRtn], ax
jnc dne7
mov [uErr], ax
dne7:
}
// If we hit an error here - we're out of luck - return an error.
// NOTE: this includes erroring out if another app created a file
// between our open (O_TEMP or O_CREATE) above & our create - the
// odds are so low we live with this - we don't screw anything up,
// we just don't get the file.
if ((*puErr = uErr) != 0)
return (-1);
// If set to R/O, O_WRITE - use this handle
if (fRO)
return (iRtn);
// OK - we have the file - close it & re-open it with sharing
FileClose (iRtn);
_asm
{
mov ah, 3Dh
mov al, byte ptr [uFileMode]
mov dx, [pFile]
int 21h // Open
mov [iRtn], ax
jnc dne8
mov [uErr], ax
dne8:
}
// if we have an error - error out, otherwise we have it
if ((*puErr = uErr) != 0)
return (-1);
}
Finish:
// Do we have a trunc or append?
if (uMode & O_TRUNC)
FileSetSize (iRtn, 0L);
if (uMode & O_APPEND)
FileSeek (iRtn, FileGetSize (iRtn));
*puErr = 0;
return (iRtn);
}